﻿#nullable enable
using Application.Service.LogCache;

namespace Application.Service.Users;

/// <summary>
/// 用户管理服务
/// <para>功能：提供用户管理的Web API接口，支持用户信息的增删改查操作</para>
/// <list type="bullet">
/// <item><description>用户信息查询：获取所有用户、单个用户详情</description></item>
/// <item><description>用户管理：创建、更新、删除用户信息</description></item>
/// <item><description>用户状态管理：启用/禁用用户账户</description></item>
/// <item><description>用户数据封装：为用户界面提供标准化的数据格式</description></item>
/// </list>
/// </summary>
[ApiDescriptionSettings(SplitCamelCase = false)]
public sealed class UserService : IDynamicApiController, ITransient, IUserService
{
    private readonly ISqlSugarClient _db;

    public UserService(ISqlSugarClient db)
    {
		_db = db;
	}

    private static UserDto Map(User u) => new(u.Id, u.UserName, u.PasswordHash, u.DisplayName, u.IsDisabled, u.CreatedAt, u.Permissions);

    /// <summary>
    /// 查询系统中所有注册用户的信息
    /// </summary>
    /// <returns>返回包含所有用户基本信息的集合</returns>
    public async Task<IEnumerable<UserDto>> GetAllAsync()
    {
        try
        {
            var users = await GetAllEntiyAsync();
            return users.Select(Map);
        }
        catch (Exception ex)
        {
            Log.Error($"获取所有用户失败!", ex);
            throw Oops.Bah($"获取所有用户失败!", ex);
        }
    }

    [SwaggerIgnore]
    public async Task<IEnumerable<User>> GetAllEntiyAsync()
    {
        var dbCopy = _db.CopyNew();
        try
        {
            var users = await dbCopy.Queryable<User>().Includes(u => u.Permissions).OrderBy(u => u.Id).ToListAsync();
            return users;
        }
        catch (Exception ex)
        {
            Log.Error($"获取所有用户失败!", ex);
            throw Oops.Bah($"获取所有用户失败!", ex);
        }
        finally
        {
            dbCopy.Close();
            dbCopy.Dispose();
        }
    }

    /// <summary>
    /// 通过用户ID精确查询特定用户的详细信息
    /// </summary>
    /// <param name="userId">用户id</param>
    /// <returns>返回指定用户的完整信息或null（用户不存在）</returns>
    public async Task<UserDto?> GetAsync(int userId)
    {
        var dbCopy = _db.CopyNew();
        try
        {
            var user = await dbCopy.Queryable<User>().InSingleAsync(userId);
            return user is null ? null : Map(user);
        }
        catch (Exception ex)
        {
            Log.Error($"获取id为{userId}的用户失败!", ex);
            throw Oops.Bah($"获取id为{userId}的用户失败!", ex);
        }
        finally
        {
            dbCopy.Close();
            dbCopy.Dispose();
        }
    }

    /// <summary>
    /// 通过用户名精确查询特定用户的详细信息
    /// </summary>
    /// <param name="username">用户名</param>
    /// <returns>返回指定用户的完整信息或null（用户不存在）</returns>
    public async Task<UserDto?> GetAsync(string username)
    {
        var dbCopy = _db.CopyNew();
        try
        {
            var user = await dbCopy.Queryable<User>().Includes(opt => opt.Permissions).Where(opt => opt.UserName == username).FirstAsync();
            return user is null ? null : Map(user);
        }
        catch (Exception ex)
        {
            Log.Error($"获取name为{username}的用户失败!", ex);
            throw Oops.Bah($"获取name为{username}的用户失败!", ex);
        }
        finally
        {
            dbCopy.Close();
            dbCopy.Dispose();
        }

    }

    /// <summary>
    /// 创建新的用户账户
    /// </summary>
    /// <param name="dto">用户创建信息</param>
    /// <returns>返回创建结果、错误信息和创建的用户信息元组</returns>
    public async Task<(bool ok, string? error, UserDto? user)> CreateAsync(UserCreateDto dto)
    {
        var dbCopy = _db.CopyNew();
        try
        {
            if (await dbCopy.Queryable<User>().AnyAsync(u => u.UserName == dto.UserName))
                return (false, $"用户名已存在: {dto.UserName}", null);

            var entity = new User
            {
                UserName = dto.UserName,
                PasswordHash = MD5Encryption.Encrypt(dto.PasswordHash,true,false),
                DisplayName = dto.DisplayName,
                IsDisabled = dto.IsDisabled,
                CreatedAt = DateTime.UtcNow
            };

            var id = await dbCopy.Insertable(entity).ExecuteReturnIdentityAsync();
            entity.Id = id;
            return (true, null, Map(entity));
        }
        catch (Exception ex)
        {
            Log.Error($"新建用户失败!", ex);
            throw Oops.Bah($"新建用户失败!", ex);
        }
        finally
        {
            dbCopy.Close();
            dbCopy.Dispose();
        }
    }

    /// <summary>
    /// 更新指定用户的基本信息和状态
    /// </summary>
    /// <param name="userId">用户ID</param>
    /// <param name="dto">用户更新信息</param>
    /// <returns>返回更新结果、错误信息和更新后的用户信息元组</returns>
    public async Task<(bool ok, string? error, UserDto? user)> UpdateAsync(int userId, UserUpdateDto dto)
    {
        var dbCopy = _db.CopyNew();
        try
        {
            var user = await dbCopy.Queryable<User>().InSingleAsync(userId);
            if (user is null) return (false, "用户不存在", null);

            if (!string.Equals(user.UserName, dto.UserName, StringComparison.Ordinal) &&
                await dbCopy.Queryable<User>().AnyAsync(u => u.UserName == dto.UserName))
            {
                return (false, $"用户名已存在: {dto.UserName}", null);
            }

            user.UserName = dto.UserName;
            if (!string.IsNullOrWhiteSpace(dto.PasswordHash))
                user.PasswordHash = MD5Encryption.Encrypt(dto.PasswordHash, true, false);
            user.DisplayName = dto.DisplayName;
            user.IsDisabled = dto.IsDisabled;

            await dbCopy.Updateable(user).ExecuteCommandAsync();
            return (true, null, Map(user));
        }
        catch (Exception ex)
        {
            Log.Error($"修改用户资料失败!", ex);
            throw Oops.Bah($"修改用户资料失败!", ex);
        }
        finally
        {
            dbCopy.Close();
            dbCopy.Dispose();
        }
    }

    /// <summary>
    /// 永久删除指定用户及其相关数据
    /// </summary>
    /// <param name="userId">用户id</param>
    /// <returns>返回删除结果和错误信息结果元组（超级管理员不可删除）</returns>
    public async Task<(bool ok, string? error)> DeleteAsync(int userId)
    {
        if (userId == 1)
        {
            throw Oops.Oh("超级管理员不能删除!");
        }
        var dbCopy = _db.CopyNew();
        try
        {
            var user = await dbCopy.Queryable<User>().InSingleAsync(userId);
            if (user is null) return (false, "用户不存在");

            var tran = await dbCopy.Ado.UseTranAsync(async () =>
            {
                await dbCopy.Deleteable<UserPermission>().Where(up => up.UserId == userId).ExecuteCommandAsync();
                await dbCopy.Deleteable<User>().In(userId).ExecuteCommandAsync();
            });

            return tran.IsSuccess ? (true, null) : (false, tran.ErrorMessage);
        }
        catch (Exception ex)
        {
            Log.Error($"删除用户失败!", ex);
            throw Oops.Bah($"删除用户失败!", ex);
        }
        finally
        {
            dbCopy.Close();
            dbCopy.Dispose();
        }
    }

    /// <summary>
    /// 查询指定用户当前拥有的所有权限
    /// </summary>
    /// <param name="userId">用户Id</param>
    /// <returns>返回用户权限查询结果和权限列表结果元组</returns>
    public async Task<(bool ok, string? error, IEnumerable<Permission> perms)> GetPermissionsAsync(int userId)
    {
        var dbCopy = _db.CopyNew();
        try
        {
            var user = await dbCopy.Queryable<User>().InSingleAsync(userId);
            if (user is null) return (false, "用户不存在", Enumerable.Empty<Permission>());

            var perms = await dbCopy.Queryable<Permission>()
                                    .InnerJoin<UserPermission>((p, up) => p.Id == up.PermissionId)
                                    .Where((p, up) => up.UserId == userId)
                                    .ToListAsync();
            return (true, null, perms);
        }
        catch (Exception ex)
        {
            Log.Error($"获取用户权限表失败!", ex);
            throw Oops.Bah($"获取用户权限表失败!", ex);
        }
        finally
        {
            dbCopy.Close();
            dbCopy.Dispose();
        }
    }

    /// <summary>
    /// 为指定用户批量设置权限列表
    /// </summary>
    /// <param name="userId">用户Id</param>
    /// <param name="permissionIds">用户权限列表</param>
    /// <returns>返回权限设置结果和错误信息结果元组</returns>
    public async Task<(bool ok, string? error)> SetPermissionsAsync(int userId, List<int> permissionIds)
    {
        var dbCopy = _db.CopyNew();
        try
        {
            var user = await dbCopy.Queryable<User>().InSingleAsync(userId);
            if (user is null) return (false, "用户不存在");

            var ids = (permissionIds ?? new List<int>()).Distinct().ToList();
            var validIds = ids.Count == 0
                ? new List<int>()
                : await dbCopy.Queryable<Permission>().Where(p => ids.Contains(p.Id)).Select(p => p.Id).ToListAsync();

            var tran = await dbCopy.Ado.UseTranAsync(async () =>
            {
                await dbCopy.Deleteable<UserPermission>().Where(up => up.UserId == userId).ExecuteCommandAsync();

                if (validIds.Count > 0)
                {
                    var rows = validIds.Select(pid => new UserPermission { UserId = userId, PermissionId = pid }).ToList();
                    await dbCopy.Insertable(rows).ExecuteCommandAsync();
                }
            });

            return tran.IsSuccess ? (true, null) : (false, tran.ErrorMessage);
        }
        catch (Exception ex)
        {
            Log.Error($"更新用户权限表失败!", ex);
            throw Oops.Bah($"更新用户权限表失败!", ex);
        }
        finally
        {
            dbCopy.Close();
            dbCopy.Dispose();
        }
    }

    /// <summary>
    /// 为指定用户添加单个权限
    /// </summary>
    /// <param name="userId">用户Id</param>
    /// <param name="permissionId">待增加权限</param>
    /// <returns>返回权限添加结果和错误信息结果元组</returns>
    public async Task<(bool ok, string? error)> AddPermissionAsync(int userId, int permissionId)
    {
        var dbCopy = _db.CopyNew();
        try
        {
            var user = await dbCopy.Queryable<User>().InSingleAsync(userId);
            if (user is null) return (false, "用户不存在");

            var permExists = await dbCopy.Queryable<Permission>().AnyAsync(p => p.Id == permissionId);
            if (!permExists) return (false, "权限不存在");

            var has = await dbCopy.Queryable<UserPermission>()
                                .AnyAsync(up => up.UserId == userId && up.PermissionId == permissionId);
            if (!has)
            {
                await dbCopy.Insertable(new UserPermission { UserId = userId, PermissionId = permissionId }).ExecuteCommandAsync();
            }
            return (true, null);
        }
        catch (Exception ex)
        {
            Log.Error($"增加权限表失败!", ex);
            throw Oops.Bah($"增加权限表失败!", ex);
        }
        finally
        {
            dbCopy.Close();
            dbCopy.Dispose();
        }
    }

    /// <summary>
    /// 从指定用户移除单个权限
    /// </summary>
    /// <param name="userId">用户Id</param>
    /// <param name="permissionId">权限Id</param>
    /// <returns>返回权限删除结果和错误信息结果元组</returns>
    public async Task<(bool ok, string? error)> RemovePermissionAsync(int userId, int permissionId)
    {
        var dbCopy = _db.CopyNew();
        try
        {
            var user = await dbCopy.Queryable<User>().InSingleAsync(userId);
            if (user is null) return (false, "用户不存在");

            await dbCopy.Deleteable<UserPermission>()
                        .Where(up => up.UserId == userId && up.PermissionId == permissionId)
                        .ExecuteCommandAsync();
            return (true, null);
        }
        catch (Exception ex)
        {
            Log.Error($"删除权限表失败!", ex);
            throw Oops.Bah($"删除权限表失败!", ex);
        }
        finally
        {
            dbCopy.Close();
            dbCopy.Dispose();
        }
    }
}

